<?php

namespace OAuth2\Server;

require_once 'Exception.php';
require_once 'Exception/Authentication.php';
/**
 * @mainpage
 * OAuth 2.0 server in PHP, originally written for
 * <a href="http://www.opendining.net/"> Open Dining</a>. Supports
 * <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-10">IETF draft v10</a>.
 *
 * Source repo has sample servers implementations for
 * <a href="http://php.net/manual/en/book.pdo.php"> PHP Data Objects</a> and
 * <a href="http://www.mongodb.org/">MongoDB</a>. Easily adaptable to other
 * storage engines.
 *
 * PHP Data Objects supports a variety of databases, including MySQL,
 * Microsoft SQL Server, SQLite, and Oracle, so you can try out the sample
 * to see how it all works.
 *
 * We're expanding the wiki to include more helpful documentation, but for
 * now, your best bet is to view the oauth.php source - it has lots of
 * comments.
 *
 * @author Tim Ridgely <tim.ridgely@gmail.com>
 * @author Aaron Parecki <aaron@parecki.com>
 * @author Edison Wong <hswong3i@pantarei-design.com>
 *
 * @see http://code.google.com/p/oauth2-php/
 */
/**
 * The default duration in seconds of the access token lifetime.
 */
define("OAUTH2_DEFAULT_ACCESS_TOKEN_LIFETIME", 3600);

/**
 * The default duration in seconds of the authorization code lifetime.
 */
define("OAUTH2_DEFAULT_AUTH_CODE_LIFETIME", 30);

/**
 * The default duration in seconds of the refresh token lifetime.
 */
define("OAUTH2_DEFAULT_REFRESH_TOKEN_LIFETIME", 1209600);


/**
 * @defgroup oauth2_section_2 Client Credentials
 * @{
 *
 * When interacting with the authorization server, the client identifies
 * itself using a client identifier and authenticates using a set of
 * client credentials. This specification provides one mechanism for
 * authenticating the client using password credentials.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-2
 */
/**
 * Regex to filter out the client identifier (described in Section 2 of IETF draft).
 *
 * IETF draft does not prescribe a format for these, however I've arbitrarily
 * chosen alphanumeric strings with hyphens and underscores, 3-32 characters
 * long.
 *
 * Feel free to change.
 */
define("OAUTH2_CLIENT_ID_REGEXP", "/^[a-z0-9-_]{3,32}$/i");

/**
 * @}
 */
/**
 * @defgroup oauth2_section_3 Obtaining End-User Authorization
 * @{
 *
 * When the client interacts with an end-user, the end-user MUST first
 * grant the client authorization to access its protected resources.
 * Once obtained, the end-user access grant is expressed as an
 * authorization code which the client uses to obtain an access token.
 * To obtain an end-user authorization, the client sends the end-user to
 * the end-user authorization endpoint.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3
 */
/**
 * Denotes "token" authorization response type.
 */
define("OAUTH2_AUTH_RESPONSE_TYPE_ACCESS_TOKEN", "token");

/**
 * Denotes "code" authorization response type.
 */
define("OAUTH2_AUTH_RESPONSE_TYPE_AUTH_CODE", "code");

/**
 * Denotes "code-and-token" authorization response type.
 */
define("OAUTH2_AUTH_RESPONSE_TYPE_CODE_AND_TOKEN", "code-and-token");

/**
 * Regex to filter out the authorization response type.
 */
define("OAUTH2_AUTH_RESPONSE_TYPE_REGEXP", "/^(token|code|code-and-token)$/");

/**
 * @}
 */
/**
 * @defgroup oauth2_section_4 Obtaining an Access Token
 * @{
 *
 * The client obtains an access token by authenticating with the
 * authorization server and presenting its access grant (in the form of
 * an authorization code, resource owner credentials, an assertion, or a
 * refresh token).
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4
 */
/**
 * Denotes "authorization_code" grant types (for token obtaining).
 */
define("OAUTH2_GRANT_TYPE_AUTH_CODE", "authorization_code");

/**
 * Denotes "password" grant types (for token obtaining).
 */
define("OAUTH2_GRANT_TYPE_USER_CREDENTIALS", "password");

/**
 * Denotes "assertion" grant types (for token obtaining).
 */
define("OAUTH2_GRANT_TYPE_ASSERTION", "assertion");

/**
 * Denotes "refresh_token" grant types (for token obtaining).
 */
define("OAUTH2_GRANT_TYPE_REFRESH_TOKEN", "refresh_token");

/**
 * Denotes "none" grant types (for token obtaining).
 */
define("OAUTH2_GRANT_TYPE_NONE", "none");

/**
 * Regex to filter out the grant type.
 */
define("OAUTH2_GRANT_TYPE_REGEXP", "/^(authorization_code|password|assertion|refresh_token|none)$/");

/**
 * @}
 */
/**
 * @defgroup oauth2_section_5 Accessing a Protected Resource
 * @{
 *
 * Clients access protected resources by presenting an access token to
 * the resource server. Access tokens act as bearer tokens, where the
 * token string acts as a shared symmetric secret. This requires
 * treating the access token with the same care as other secrets (e.g.
 * end-user passwords). Access tokens SHOULD NOT be sent in the clear
 * over an insecure channel.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5
 */
/**
 * Used to define the name of the OAuth access token parameter (POST/GET/etc.).
 *
 * IETF Draft sections 5.1.2 and 5.1.3 specify that it should be called
 * "oauth_token" but other implementations use things like "access_token".
 *
 * I won't be heartbroken if you change it, but it might be better to adhere
 * to the spec.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.1.2
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.1.3
 */
define("OAUTH2_TOKEN_PARAM_NAME", "oauth_token");

/**
 * @}
 */
/**
 * @defgroup oauth2_http_status HTTP status code
 * @{
 */
/**
 * "Found" HTTP status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3
 */
define("OAUTH2_HTTP_FOUND", "302 Found");

/**
 * "Bad Request" HTTP status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_HTTP_BAD_REQUEST", "400 Bad Request");

/**
 * "Unauthorized" HTTP status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_HTTP_UNAUTHORIZED", "401 Unauthorized");

/**
 * "Forbidden" HTTP status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_HTTP_FORBIDDEN", "403 Forbidden");

/**
 * @}
 */
/**
 * @defgroup oauth2_error Error handling
 * @{
 *
 * @todo Extend for i18n.
 */
/**
 * The request is missing a required parameter, includes an unsupported
 * parameter or parameter value, or is otherwise malformed.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_ERROR_INVALID_REQUEST", "invalid_request");

/**
 * The client identifier provided is invalid.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 */
define("OAUTH2_ERROR_INVALID_CLIENT", "invalid_client");

/**
 * The client is not authorized to use the requested response type.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 */
define("OAUTH2_ERROR_UNAUTHORIZED_CLIENT", "unauthorized_client");

/**
 * The redirection URI provided does not match a pre-registered value.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 */
define("OAUTH2_ERROR_REDIRECT_URI_MISMATCH", "redirect_uri_mismatch");

/**
 * The end-user or authorization server denied the request.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 */
define("OAUTH2_ERROR_USER_DENIED", "access_denied");

/**
 * The requested response type is not supported by the authorization server.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 */
define("OAUTH2_ERROR_UNSUPPORTED_RESPONSE_TYPE", "unsupported_response_type");

/**
 * The requested scope is invalid, unknown, or malformed.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2.1
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 */
define("OAUTH2_ERROR_INVALID_SCOPE", "invalid_scope");

/**
 * The provided access grant is invalid, expired, or revoked (e.g. invalid
 * assertion, expired authorization token, bad end-user password credentials,
 * or mismatching authorization code and redirection URI).
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 */
define("OAUTH2_ERROR_INVALID_GRANT", "invalid_grant");

/**
 * The access grant included - its type or another attribute - is not
 * supported by the authorization server.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.3.1
 */
define("OAUTH2_ERROR_UNSUPPORTED_GRANT_TYPE", "unsupported_grant_type");

/**
 * The access token provided is invalid. Resource servers SHOULD use this
 * error code when receiving an expired token which cannot be refreshed to
 * indicate to the client that a new authorization is necessary. The resource
 * server MUST respond with the HTTP 401 (Unauthorized) status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_ERROR_INVALID_TOKEN", "invalid_token");

/**
 * The access token provided has expired. Resource servers SHOULD only use
 * this error code when the client is expected to be able to handle the
 * response and request a new access token using the refresh token issued
 * with the expired access token. The resource server MUST respond with the
 * HTTP 401 (Unauthorized) status code.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_ERROR_EXPIRED_TOKEN", "expired_token");

/**
 * The request requires higher privileges than provided by the access token.
 * The resource server SHOULD respond with the HTTP 403 (Forbidden) status
 * code and MAY include the "scope" attribute with the scope necessary to
 * access the protected resource.
 *
 * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.2.1
 */
define("OAUTH2_ERROR_INSUFFICIENT_SCOPE", "insufficient_scope");

/**
 * @}
 */

/**
 * OAuth2.0 draft v10 server-side implementation.
 *
 * @author Originally written by Tim Ridgely <tim.ridgely@gmail.com>.
 * @author Updated to draft v10 by Aaron Parecki <aaron@parecki.com>.
 * @author Debug, coding style clean up and documented by Edison Wong <hswong3i@pantarei-design.com>.
 */
abstract class ServerAbstract
{

    /**
     * Array of persistent variables stored.
     */
    protected $conf = array();

    /**
     * Returns a persistent variable.
     *
     * To avoid problems, always use lower case for persistent variable names.
     *
     * @param $name
     *   The name of the variable to return.
     * @param $default
     *   The default value to use if this variable has never been set.
     *
     * @return
     *   The value of the variable.
     */
    public function getVariable($name, $default = NULL)
    {
        return isset($this->conf[$name]) ? $this->conf[$name] : $default;
    }

    /**
     * Sets a persistent variable.
     *
     * To avoid problems, always use lower case for persistent variable names.
     *
     * @param $name
     *   The name of the variable to set.
     * @param $value
     *   The value to set.
     */
    public function setVariable($name, $value)
    {
        $this->conf[$name] = $value;
        return $this;
    }

    // Subclasses must implement the following functions.

    /**
     * Make sure that the client credentials is valid.
     *
     * @param $client_id
     *   Client identifier to be check with.
     * @param $client_secret
     *   (optional) If a secret is required, check that they've given the right one.
     *
     * @return
     *   TRUE if client credentials are valid, and MUST return FALSE if invalid.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-2.1
     *
     * @ingroup oauth2_section_2
     */
    abstract protected function checkClientCredentials($client_id, $client_secret = NULL);

    /**
     * Get the registered redirect URI of corresponding client_id.
     *
     * OAuth says we should store request URIs for each registered client.
     * Implement this function to grab the stored URI for a given client id.
     *
     * @param $client_id
     *   Client identifier to be check with.
     *
     * @return
     *   Registered redirect URI of corresponding client identifier, and MUST
     *   return FALSE if the given client does not exist or is invalid.
     *
     * @ingroup oauth2_section_3
     */
    abstract protected function getRedirectUri($client_id);

    /**
     * Look up the supplied oauth_token from storage.
     *
     * We need to retrieve access token data as we create and verify tokens.
     *
     * @param $oauth_token
     *   oauth_token to be check with.
     *
     * @return
     *   An associative array as below, and return NULL if the supplied oauth_token
     *   is invalid:
     *   - client_id: Stored client identifier.
     *   - expires: Stored expiration in unix timestamp.
     *   - scope: (optional) Stored scope values in space-separated string.
     *
     * @ingroup oauth2_section_5
     */
    abstract protected function getAccessToken($oauth_token);

    /**
     * Store the supplied access token values to storage.
     *
     * We need to store access token data as we create and verify tokens.
     *
     * @param $oauth_token
     *   oauth_token to be stored.
     * @param $client_id
     *   Client identifier to be stored.
     * @param $expires
     *   Expiration to be stored.
     * @param $scope
     *   (optional) Scopes to be stored in space-separated string.
     *
     * @ingroup oauth2_section_4
     */
    abstract protected function setAccessToken($oauth_token, $client_id, $expires, $scope = NULL);

    // Stuff that should get overridden by subclasses.
    //
  // I don't want to make these abstract, because then subclasses would have
    // to implement all of them, which is too much work.
    //
  // So they're just stubs. Override the ones you need.

    /**
     * Return supported grant types.
     *
     * You should override this function with something, or else your OAuth
     * provider won't support any grant types!
     *
     * @return
     *   A list as below. If you support all grant types, then you'd do:
     * @code
     * return array(
     *   OAUTH2_GRANT_TYPE_AUTH_CODE,
     *   OAUTH2_GRANT_TYPE_USER_CREDENTIALS,
     *   OAUTH2_GRANT_TYPE_ASSERTION,
     *   OAUTH2_GRANT_TYPE_REFRESH_TOKEN,
     *   OAUTH2_GRANT_TYPE_NONE,
     * );
     * @endcode
     *
     * @ingroup oauth2_section_4
     */
    protected function getSupportedGrantTypes()
    {
        return array();
    }

    /**
     * Return supported authorization response types.
     *
     * You should override this function with your supported response types.
     *
     * @return
     *   A list as below. If you support all authorization response types,
     *   then you'd do:
     * @code
     * return array(
     *   OAUTH2_AUTH_RESPONSE_TYPE_AUTH_CODE,
     *   OAUTH2_AUTH_RESPONSE_TYPE_ACCESS_TOKEN,
     *   OAUTH2_AUTH_RESPONSE_TYPE_CODE_AND_TOKEN,
     * );
     * @endcode
     *
     * @ingroup oauth2_section_3
     */
    public function getSupportedAuthResponseTypes()
    {
        return array(
            OAUTH2_AUTH_RESPONSE_TYPE_AUTH_CODE,
            OAUTH2_AUTH_RESPONSE_TYPE_ACCESS_TOKEN,
            OAUTH2_AUTH_RESPONSE_TYPE_CODE_AND_TOKEN
        );
    }

    /**
     * Return supported scopes.
     *
     * If you want to support scope use, then have this function return a list
     * of all acceptable scopes (used to throw the invalid-scope error).
     *
     * @return
     *   A list as below, for example:
     * @code
     * return array(
     *   'my-friends',
     *   'photos',
     *   'whatever-else',
     * );
     * @endcode
     *
     * @ingroup oauth2_section_3
     */
    protected function getSupportedScopes()
    {
        return array();
    }

    /**
     * Check restricted authorization response types of corresponding Client
     * identifier.
     *
     * If you want to restrict clients to certain authorization response types,
     * override this function.
     *
     * @param $client_id
     *   Client identifier to be check with.
     * @param $response_type
     *   Authorization response type to be check with, would be one of the
     *   values contained in OAUTH2_AUTH_RESPONSE_TYPE_REGEXP.
     *
     * @return
     *   TRUE if the authorization response type is supported by this
     *   client identifier, and FALSE if it isn't.
     *
     * @ingroup oauth2_section_3
     */
    public function checkRestrictedAuthResponseType($client_id, $response_type)
    {
        return TRUE;
    }

    /**
     * Check restricted grant types of corresponding client identifier.
     *
     * If you want to restrict clients to certain grant types, override this
     * function.
     *
     * @param $client_id
     *   Client identifier to be check with.
     * @param $grant_type
     *   Grant type to be check with, would be one of the values contained in
     *   OAUTH2_GRANT_TYPE_REGEXP.
     *
     * @return
     *   TRUE if the grant type is supported by this client identifier, and
     *   FALSE if it isn't.
     *
     * @ingroup oauth2_section_4
     */
    protected function checkRestrictedGrantType($client_id, $grant_type)
    {
        return TRUE;
    }

    // Functions that help grant access tokens for various grant types.

    /**
     * Fetch authorization code data (probably the most common grant type).
     *
     * Retrieve the stored data for the given authorization code.
     *
     * Required for OAUTH2_GRANT_TYPE_AUTH_CODE.
     *
     * @param $code
     *   Authorization code to be check with.
     *
     * @return
     *   An associative array as below, and NULL if the code is invalid:
     *   - client_id: Stored client identifier.
     *   - redirect_uri: Stored redirect URI.
     *   - expires: Stored expiration in unix timestamp.
     *   - scope: (optional) Stored scope values in space-separated string.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.1
     *
     * @ingroup oauth2_section_4
     */
    protected function getAuthCode($code)
    {
        return NULL;
    }

    /**
     * Take the provided authorization code values and store them somewhere.
     *
     * This function should be the storage counterpart to getAuthCode().
     *
     * If storage fails for some reason, we're not currently checking for
     * any sort of success/failure, so you should bail out of the script
     * and provide a descriptive fail message.
     *
     * Required for OAUTH2_GRANT_TYPE_AUTH_CODE.
     *
     * @param $code
     *   Authorization code to be stored.
     * @param $client_id
     *   Client identifier to be stored.
     * @param $redirect_uri
     *   Redirect URI to be stored.
     * @param $expires
     *   Expiration to be stored.
     * @param $scope
     *   (optional) Scopes to be stored in space-separated string.
     *
     * @ingroup oauth2_section_4
     */
    protected function setAuthCode($code, $client_id, $redirect_uri, $expires, $scope = NULL)
    {
        
    }

    /**
     * Grant access tokens for basic user credentials.
     *
     * Check the supplied username and password for validity.
     *
     * You can also use the $client_id param to do any checks required based
     * on a client, if you need that.
     *
     * Required for OAUTH2_GRANT_TYPE_USER_CREDENTIALS.
     *
     * @param $client_id
     *   Client identifier to be check with.
     * @param $username
     *   Username to be check with.
     * @param $password
     *   Password to be check with.
     *
     * @return
     *   TRUE if the username and password are valid, and FALSE if it isn't.
     *   Moreover, if the username and password are valid, and you want to
     *   verify the scope of a user's access, return an associative array
     *   with the scope values as below. We'll check the scope you provide
     *   against the requested scope before providing an access token:
     * @code
     * return array(
     *   'scope' => <stored scope values (space-separated string)>,
     * );
     * @endcode
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.2
     *
     * @ingroup oauth2_section_4
     */
    protected function checkUserCredentials($client_id, $username, $password)
    {
        return FALSE;
    }

    /**
     * Grant access tokens for assertions.
     *
     * Check the supplied assertion for validity.
     *
     * You can also use the $client_id param to do any checks required based
     * on a client, if you need that.
     *
     * Required for OAUTH2_GRANT_TYPE_ASSERTION.
     *
     * @param $client_id
     *   Client identifier to be check with.
     * @param $assertion_type
     *   The format of the assertion as defined by the authorization server.
     * @param $assertion
     *   The assertion.
     *
     * @return
     *   TRUE if the assertion is valid, and FALSE if it isn't. Moreover, if
     *   the assertion is valid, and you want to verify the scope of an access
     *   request, return an associative array with the scope values as below.
     *   We'll check the scope you provide against the requested scope before
     *   providing an access token:
     * @code
     * return array(
     *   'scope' => <stored scope values (space-separated string)>,
     * );
     * @endcode
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.3
     *
     * @ingroup oauth2_section_4
     */
    protected function checkAssertion($client_id, $assertion_type, $assertion)
    {
        return FALSE;
    }

    /**
     * Grant refresh access tokens.
     *
     * Retrieve the stored data for the given refresh token.
     *
     * Required for OAUTH2_GRANT_TYPE_REFRESH_TOKEN.
     *
     * @param $refresh_token
     *   Refresh token to be check with.
     *
     * @return
     *   An associative array as below, and NULL if the refresh_token is
     *   invalid:
     *   - client_id: Stored client identifier.
     *   - expires: Stored expiration unix timestamp.
     *   - scope: (optional) Stored scope values in space-separated string.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4.1.4
     *
     * @ingroup oauth2_section_4
     */
    protected function getRefreshToken($refresh_token)
    {
        return NULL;
    }

    /**
     * Take the provided refresh token values and store them somewhere.
     *
     * This function should be the storage counterpart to getRefreshToken().
     *
     * If storage fails for some reason, we're not currently checking for
     * any sort of success/failure, so you should bail out of the script
     * and provide a descriptive fail message.
     *
     * Required for OAUTH2_GRANT_TYPE_REFRESH_TOKEN.
     *
     * @param $refresh_token
     *   Refresh token to be stored.
     * @param $client_id
     *   Client identifier to be stored.
     * @param $expires
     *   expires to be stored.
     * @param $scope
     *   (optional) Scopes to be stored in space-separated string.
     *
     * @ingroup oauth2_section_4
     */
    protected function setRefreshToken($refresh_token, $client_id, $expires, $scope = NULL)
    {
        return;
    }

    /**
     * Expire a used refresh token.
     *
     * This is not explicitly required in the spec, but is almost implied.
     * After granting a new refresh token, the old one is no longer useful and
     * so should be forcibly expired in the data store so it can't be used again.
     *
     * If storage fails for some reason, we're not currently checking for
     * any sort of success/failure, so you should bail out of the script
     * and provide a descriptive fail message.
     *
     * @param $refresh_token
     *   Refresh token to be expirse.
     *
     * @ingroup oauth2_section_4
     */
    protected function unsetRefreshToken($refresh_token)
    {
        return;
    }

    /**
     * Grant access tokens for the "none" grant type.
     *
     * Not really described in the IETF Draft, so I just left a method
     * stub... Do whatever you want!
     *
     * Required for OAUTH2_GRANT_TYPE_NONE.
     *
     * @ingroup oauth2_section_4
     */
    protected function checkNoneAccess($client_id)
    {
        return FALSE;
    }

    /**
     * Get default authentication realm for WWW-Authenticate header.
     *
     * Change this to whatever authentication realm you want to send in a
     * WWW-Authenticate header.
     *
     * @return
     *   A string that you want to send in a WWW-Authenticate header.
     *
     * @ingroup oauth2_error
     */
    public function getDefaultAuthenticationRealm()
    {
        return "Service";
    }

    // End stuff that should get overridden.

    /**
     * Creates an OAuth2.0 server-side instance.
     *
     * @param $config
     *   An associative array as below:
     *   - access_token_lifetime: (optional) The lifetime of access token in
     *     seconds.
     *   - auth_code_lifetime: (optional) The lifetime of authorization code in
     *     seconds.
     *   - refresh_token_lifetime: (optional) The lifetime of refresh token in
     *     seconds.
     *   - display_error: (optional) Whether to show verbose error messages in
     *     the response.
     */
    public function __construct($config = array())
    {
        foreach ($config as $name => $value)
        {
            $this->setVariable($name, $value);
        }
    }

    // Resource protecting (Section 5).

    /**
     * Check that a valid access token has been provided.
     *
     * The scope parameter defines any required scope that the token must have.
     * If a scope param is provided and the token does not have the required
     * scope, we bounce the request.
     *
     * Some implementations may choose to return a subset of the protected
     * resource (i.e. "public" data) if the user has not provided an access
     * token or if the access token is invalid or expired.
     *
     * The IETF spec says that we should send a 401 Unauthorized header and
     * bail immediately so that's what the defaults are set to.
     *
     * @param $scope
     *   A space-separated string of required scope(s), if you want to check
     *   for scope.
     * @param $exit_not_present
     *   If TRUE and no access token is provided, send a 401 header and exit,
     *   otherwise return FALSE.
     * @param $exit_invalid
     *   If TRUE and the implementation of getAccessToken() returns NULL, exit,
     *   otherwise return FALSE.
     * @param $exit_expired
     *   If TRUE and the access token has expired, exit, otherwise return FALSE.
     * @param $exit_scope
     *   If TRUE the access token does not have the required scope(s), exit,
     *   otherwise return FALSE.
     * @param $realm
     *   If you want to specify a particular realm for the WWW-Authenticate
     *   header, supply it here.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5
     *
     * @ingroup oauth2_section_5
     */
    public function verifyAccessToken($token_param, $scope = NULL, $exit_not_present = TRUE, $exit_invalid = TRUE, $exit_expired = TRUE, $exit_scope = TRUE, $realm = NULL)
    {
        if ($token_param === FALSE) // Access token was not provided
            if ($exit_not_present)
            {
                throw new \OAuth2\Server\Exception\Authentication(OAUTH2_HTTP_BAD_REQUEST, $realm, OAUTH2_ERROR_INVALID_REQUEST, 'The request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, uses more than one method for including an access token, or is otherwise malformed.', NULL, $scope);
            } else
            {
                return FALSE;
            }
        // Get the stored token data (from the implementing subclass)
        $token = $this->getAccessToken($token_param);
        if ($token === NULL)
            if ($exit_invalid)
            {
                throw new \OAuth2\Server\Exception\Authentication(OAUTH2_HTTP_UNAUTHORIZED, $realm, OAUTH2_ERROR_INVALID_TOKEN, 'The access token provided is invalid.', NULL, $scope);
            } else
            {
                return false;
            }


        // Check token expiration (I'm leaving this check separated, later we'll fill in better error messages)
        if (isset($token["expires"]) && time() > $token["expires"])
            if ($exit_expired)
            {
                throw new \OAuth2\Server\Exception\Authentication(OAUTH2_HTTP_UNAUTHORIZED, $realm, OAUTH2_ERROR_EXPIRED_TOKEN, 'The access token provided has expired.', NULL, $scope);
            } else
            {
                return FALSE;
            }

        // Check scope, if provided
        // If token doesn't have a scope, it's NULL/empty, or it's insufficient, then throw an error
        if ($scope && (!isset($token["scope"]) || !$token["scope"] || !$this->checkScope($scope, $token["scope"])))
            if ($exit_scope)
            {
                throw new \OAuth2\Server\Exception\Authentication(OAUTH2_HTTP_FORBIDDEN, $realm, OAUTH2_ERROR_INSUFFICIENT_SCOPE, 'The request requires higher privileges than provided by the access token.', NULL, $scope);
            } else
            {
                return FALSE;
            }
        return TRUE;
    }

    /**
     * Check if everything in required scope is contained in available scope.
     *
     * @param $required_scope
     *   Required scope to be check with.
     * @param $available_scope
     *   Available scope to be compare with.
     *
     * @return
     *   TRUE if everything in required scope is contained in available scope,
     *   and False if it isn't.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5
     *
     * @ingroup oauth2_section_5
     */
    protected function checkScope($required_scope, $available_scope)
    {
        // The required scope should match or be a subset of the available scope
        if (!is_array($required_scope))
            $required_scope = explode(" ", $required_scope);

        if (!is_array($available_scope))
            $available_scope = explode(" ", $available_scope);

        return (count(array_diff($required_scope, $available_scope)) == 0);
    }

    // Access token granting (Section 4).

    /**
     * Grant or deny a requested access token.
     *
     * This would be called from the "/token" endpoint as defined in the spec.
     * Obviously, you can call your endpoint whatever you want.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-4
     *
     * @ingroup oauth2_section_4
     * @param array $input Most likely output of getGrantAccessTokenInput() method
     * 
     */
    public function grantAccessToken($client, $grant_type, $code, $redirect_uri, $username, $password, $assertion_type, $assertion, $refresh_token, $scope)
    {

        // Grant Type must be specified.
        if (!$grant_type)
        {
            throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'Invalid grant_type parameter or parameter missing');
        }

        // Make sure we've implemented the requested grant type
        if (!in_array($grant_type, $this->getSupportedGrantTypes()))
        {
            throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_UNSUPPORTED_GRANT_TYPE, 'Requested grand type not implemented');
        }

        // Authorize the client
        //$client = $this->getClientCredentials();

        if ($this->checkClientCredentials($client[0], $client[1]) === FALSE)
        {
            throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_CLIENT, 'Invalid client');
        }

        if (!$this->checkRestrictedGrantType($client[0], $grant_type))
        {
            throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_UNAUTHORIZED_CLIENT, 'Unauthorized client');
        }

        // Do the granting
        switch ($grant_type)
        {
            case OAUTH2_GRANT_TYPE_AUTH_CODE:
                if (!$code || !$redirect_uri)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'Invalid request');
                }

                $stored = $this->getAuthCode($code);

                // Ensure that the input uri starts with the stored uri
                if ($stored === NULL || (strcasecmp(substr($redirect_uri, 0, strlen($stored["redirect_uri"])), $stored["redirect_uri"]) !== 0) || $client[0] != $stored["client_id"])
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT, 'Invalid grant');
                }

                if ($stored["expires"] < time())
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_EXPIRED_TOKEN, 'Token has expired');
                }

                break;
            case OAUTH2_GRANT_TYPE_USER_CREDENTIALS:
                if (!$username || !$password)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'Missing parameters. "username" and "password" required');
                }

                $stored = $this->checkUserCredentials($client[0], $username, $password);

                if ($stored === FALSE)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT, 'Invalid grant');
                }

                break;
            case OAUTH2_GRANT_TYPE_ASSERTION:
                if (!$assertion_type || !$assertion)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'Invalid request');
                }

                $stored = $this->checkAssertion($client[0], $assertion_type, $assertion);

                if ($stored === FALSE)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT, 'Invalid grant');
                }

                break;
            case OAUTH2_GRANT_TYPE_REFRESH_TOKEN:
                if (!$input["refresh_token"])
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'No "refresh_token" parameter found');
                }

                $stored = $this->getRefreshToken($input["refresh_token"]);

                if ($stored === NULL || $client[0] != $stored["client_id"])
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_GRANT, 'Invalid grant');
                }

                if ($stored["expires"] < time())
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_EXPIRED_TOKEN, 'Token has expired');
                }

                // store the refresh token locally so we can delete it when a new refresh token is generated
                $this->setVariable('_old_refresh_token', $stored["token"]);

                break;
            case OAUTH2_GRANT_TYPE_NONE:
                $stored = $this->checkNoneAccess($client[0]);

                if ($stored === FALSE)
                {
                    throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_REQUEST, 'Invalid request');
                }
        }

        // Check scope, if provided
        if ($scope && (!is_array($stored) || !isset($stored["scope"]) || !$this->checkScope($scope, $stored["scope"])))
        {
            throw new \OAuth2\Server\Exception(OAUTH2_HTTP_BAD_REQUEST, OAUTH2_ERROR_INVALID_SCOPE, 'Invalid scope');
        }

        if (!$scope)
        {
            $scope = NULL;
        }

        $token = $this->createAccessToken($client[0], $scope);

        return $token;
    }

    // End-user/client Authorization (Section 3 of IETF Draft).

    /**
     * Redirect the user appropriately after approval.
     *
     * After the user has approved or denied the access request the
     * authorization server should call this function to redirect the user
     * appropriately.
     *
     * @param $is_authorized
     *   TRUE or FALSE depending on whether the user authorized the access.
     * @param $params
     *   An associative array as below:
     *   - response_type: The requested response: an access token, an
     *     authorization code, or both.
     *   - client_id: The client identifier as described in Section 2.
     *   - redirect_uri: An absolute URI to which the authorization server
     *     will redirect the user-agent to when the end-user authorization
     *     step is completed.
     *   - scope: (optional) The scope of the access request expressed as a
     *     list of space-delimited strings.
     *   - state: (optional) An opaque value used by the client to maintain
     *     state between the request and callback.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3
     *
     * @ingroup oauth2_section_3
     */
    public function finishClientAuthorization($client_id, $redirect_uri, $response_type, $scope = null, $state = null)
    {

        if ($state !== NULL)
        {
            $result["query"]["state"] = $state;
        }

        if ($response_type == OAUTH2_AUTH_RESPONSE_TYPE_AUTH_CODE || $response_type == OAUTH2_AUTH_RESPONSE_TYPE_CODE_AND_TOKEN)
        {
            $result["query"]["code"] = $this->createAuthCode($client_id, $redirect_uri, $scope);
            return $this->getRedirectHeaders($redirect_uri, $result);
        }

        if ($response_type == OAUTH2_AUTH_RESPONSE_TYPE_ACCESS_TOKEN || $response_type == OAUTH2_AUTH_RESPONSE_TYPE_CODE_AND_TOKEN)
        {
            $result["fragment"] = $this->createAccessToken($client_id, $scope);
            return $this->getRedirectHeaders($redirect_uri, $result);
        }

        return false;
    }

    // Other/utility functions.

    /**
     * Redirect the user agent.
     *
     * Handle both redirect for success or error response.
     *
     * @param $redirect_uri
     *   An absolute URI to which the authorization server will redirect
     *   the user-agent to when the end-user authorization step is completed.
     * @param $params
     *   Parameters to be pass though buildUri().
     *
     * @ingroup oauth2_section_3
     */
    abstract function doRedirectUriCallback(array $headers);

    /**
     * Redirect the user agent.
     *
     * Handle both redirect for success or error response.
     *
     * @param $redirect_uri
     *   An absolute URI to which the authorization server will redirect
     *   the user-agent to when the end-user authorization step is completed.
     * @param $params
     *   Parameters to be pass though buildUri().
     *
     * @ingroup oauth2_section_3
     */
    public function getRedirectHeaders($redirect_uri, $params)
    {
        $headers = array();
        $headers[] = "HTTP/1.1 " . OAUTH2_HTTP_FOUND;
        $headers[] = "Location: " . $this->buildUri($redirect_uri, $params);
        return $headers;
    }

    /**
     * Build the absolute URI based on supplied URI and parameters.
     *
     * @param $uri
     *   An absolute URI.
     * @param $params
     *   Parameters to be append as GET.
     *
     * @return
     *   An absolute URI with supplied parameters.
     *
     * @ingroup oauth2_section_3
     */
    protected function buildUri($uri, $params)
    {
        $parse_url = parse_url($uri);

        // Add our params to the parsed uri
        foreach ($params as $k => $v)
        {
            if (isset($parse_url[$k]))
                $parse_url[$k] .= "&" . http_build_query($v);
            else
                $parse_url[$k] = http_build_query($v);
        }

        // Put humpty dumpty back together
        return
        ((isset($parse_url["scheme"])) ? $parse_url["scheme"] . "://" : "")
        . ((isset($parse_url["user"])) ? $parse_url["user"] . ((isset($parse_url["pass"])) ? ":" . $parse_url["pass"] : "") . "@" : "")
        . ((isset($parse_url["host"])) ? $parse_url["host"] : "")
        . ((isset($parse_url["port"])) ? ":" . $parse_url["port"] : "")
        . ((isset($parse_url["path"])) ? $parse_url["path"] : "")
        . ((isset($parse_url["query"])) ? "?" . $parse_url["query"] : "")
        . ((isset($parse_url["fragment"])) ? "#" . $parse_url["fragment"] : "");
    }

    /**
     * Handle the creation of access token, also issue refresh token if support.
     *
     * This belongs in a separate factory, but to keep it simple, I'm just
     * keeping it here.
     *
     * @param $client_id
     *   Client identifier related to the access token.
     * @param $scope
     *   (optional) Scopes to be stored in space-separated string.
     *
     * @ingroup oauth2_section_4
     */
    protected function createAccessToken($client_id, $scope = NULL)
    {
        $token = array(
            "access_token" => $this->genAccessToken(),
            "expires_in" => $this->getVariable('access_token_lifetime', OAUTH2_DEFAULT_ACCESS_TOKEN_LIFETIME),
            "scope" => $scope
        );

        $this->setAccessToken($token["access_token"], $client_id, time() + $this->getVariable('access_token_lifetime', OAUTH2_DEFAULT_ACCESS_TOKEN_LIFETIME), $scope);

        // Issue a refresh token also, if we support them
        if (in_array(OAUTH2_GRANT_TYPE_REFRESH_TOKEN, $this->getSupportedGrantTypes()))
        {
            $token["refresh_token"] = $this->genAccessToken();
            $this->setRefreshToken($token["refresh_token"], $client_id, time() + $this->getVariable('refresh_token_lifetime', OAUTH2_DEFAULT_REFRESH_TOKEN_LIFETIME), $scope);
            // If we've granted a new refresh token, expire the old one
            if ($this->getVariable('_old_refresh_token'))
                $this->unsetRefreshToken($this->getVariable('_old_refresh_token'));
        }

        return $token;
    }

    /**
     * Handle the creation of auth code.
     *
     * This belongs in a separate factory, but to keep it simple, I'm just
     * keeping it here.
     *
     * @param $client_id
     *   Client identifier related to the access token.
     * @param $redirect_uri
     *   An absolute URI to which the authorization server will redirect the
     *   user-agent to when the end-user authorization step is completed.
     * @param $scope
     *   (optional) Scopes to be stored in space-separated string.
     *
     * @ingroup oauth2_section_3
     */
    protected function createAuthCode($client_id, $redirect_uri, $scope = NULL)
    {
        $code = $this->genAuthCode();
        $this->setAuthCode($code, $client_id, $redirect_uri, time() + $this->getVariable('auth_code_lifetime', OAUTH2_DEFAULT_AUTH_CODE_LIFETIME), $scope);
        return $code;
    }

    /**
     * Generate unique access token.
     *
     * Implementing classes may want to override these function to implement
     * other access token or auth code generation schemes.
     *
     * @return
     *   An unique access token.
     *
     * @ingroup oauth2_section_4
     */
    protected function genAccessToken()
    {
        return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
    }

    /**
     * Generate unique auth code.
     *
     * Implementing classes may want to override these function to implement
     * other access token or auth code generation schemes.
     *
     * @return
     *   An unique auth code.
     *
     * @ingroup oauth2_section_3
     */
    protected function genAuthCode()
    {
        return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid())));
    }

    /**
     * Redirect the end-user's user agent with error message.
     *
     * @param $redirect_uri
     *   An absolute URI to which the authorization server will redirect the
     *   user-agent to when the end-user authorization step is completed.
     * @param $error
     *   A single error code as described in Section 3.2.1.
     * @param $error_description
     *   (optional) A human-readable text providing additional information,
     *   used to assist in the understanding and resolution of the error
     *   occurred.
     * @param $error_uri
     *   (optional) A URI identifying a human-readable web page with
     *   information about the error, used to provide the end-user with
     *   additional information about the error.
     * @param $state
     *   (optional) REQUIRED if the "state" parameter was present in the client
     *   authorization request. Set to the exact value received from the client.
     *
     * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-3.2
     *
     * @ingroup oauth2_error
     */
    protected function errorDoRedirectUriCallback($redirect_uri, $error, $error_description = NULL, $error_uri = NULL, $state = NULL)
    {
        $result["query"]["error"] = $error;

        if ($state)
            $result["query"]["state"] = $state;

        if ($this->getVariable('display_error') && $error_description)
            $result["query"]["error_description"] = $error_description;

        if ($this->getVariable('display_error') && $error_uri)
            $result["query"]["error_uri"] = $error_uri;

        return $this->getRedirectHeaders($redirect_uri, $result);
    }

}
